/*
 * BCore.h
 *
 *  Created on: Jun 12, 2013
 *      Author: dan
 */

#ifndef BCORE_H_
#define BCORE_H_

#include <iostream>
#include <sstream>
#include <map>
using namespace std;

#include <boost/thread.hpp>
using namespace boost;

#include "XMLLogger.hpp"
using namespace logger;


#define SYNCHRONIZED mutex::scoped_lock synchronized_block(internal_mutex);

class Behavior{
private:
	Behavior* superPtr;
	int terminated;
	static const int not_terminated=0;
	mutex internal_mutex;

	inline bool isRoot()const{ return superPtr==0; }
	inline Behavior& super()const{ return *superPtr; }

public:
	static const int result_preepted=-1;
	static const int result_success=0;
	static const int result_fault=0;

public:
	Behavior(): superPtr(0), terminated(not_terminated) {
	}

	Behavior(Behavior& super): superPtr(&super), terminated(not_terminated) {
	}

	virtual ~Behavior() {
	}

	virtual int run()=0;

	int terminatedCode(){ SYNCHRONIZED
		if( terminated != 0 ) return terminated;
		if( isRoot() ) return not_terminated;
		return super().terminatedCode();
	}
	bool isTerminated(){
		return terminatedCode()!=0;
	}
	void terminate(int code){ SYNCHRONIZED
		terminated = code;
	}
};

class Parallel{

	class StopCondition{
		friend class Behavior;
		friend class Parallel;
		condition_variable& cond;
		mutex& internal_mutex;
		Behavior*& done;
		int& code;
		StopCondition(boost::mutex& mtx, boost::condition_variable& cond, Behavior*& done, int& code):cond(cond), internal_mutex(mtx), done(done), code(code){}
		void stop(int stop_code, Behavior* stop_index){ SYNCHRONIZED
			if(!done) code = stop_code;
			done = stop_index;
			cond.notify_one();
		}
	};

	int stopResult;
	Behavior* done;
	condition_variable stopped;
	mutable mutex internal_mutex;
	thread_group threads;
	StopCondition stopCondition;
	vector<Behavior*> behs;

	void runInThread(Behavior* beh){
		int code = beh->run();
		stopCondition.stop(code, beh);
	}

	int _wait(mutex::scoped_lock& synchronized_block){
		if( done ) return stopResult;
		stopped.wait(synchronized_block);
		return stopResult;
	}

public:
	Parallel():done(0),stopCondition(internal_mutex, stopped, done, stopResult){
	}

	Behavior& fistStopped()const{ SYNCHRONIZED
		return *done;
	}

	void run(Behavior& beh){ SYNCHRONIZED
		Behavior* behPtr = &beh;
		behs.push_back(behPtr);
		threads.add_thread(new thread(boost::bind(&Parallel::runInThread, this, behPtr)));
	}

	void join(){
		threads.join_all();
	}

	int wait(){ SYNCHRONIZED
		return _wait(synchronized_block);
	}

	int untilFirstExit(){
		if(behs.size()==0) return 0;
		int res;
		{ SYNCHRONIZED
			res = _wait(synchronized_block);
			for(size_t i=0;i<behs.size();i++){ behs[i]->terminate(Behavior::result_preepted); }
		}
		join();
		return res;
	}
	int untilAllExit(){
		join();
		return stopResult;
	}

	int execute(){ return untilFirstExit(); }
};

class Sequancer{
	vector<Behavior*> behs;

public:
	Sequancer(){}
	void run(Behavior& beh){

	}
	int execute(){
		for(size_t i=0;i<behs.size();i++){
			int res = behs[i]->run();
			if( res!= Behavior::result_success ) return res;
		}
		return Behavior::result_success;
	}
};
class Selector{
	vector<Behavior*> behs;

public:
	Selector(){}
	void run(Behavior& beh){

	}
	int execute(){
		for(size_t i=0;i<behs.size();i++){
			int res = behs[i]->run();
			if( res== Behavior::result_success ) return res;
		}
		return Behavior::result_fault;
	}
};

#undef SYNCHRONIZED

#endif /* BCORE_H_ */
